/*

* ------------------------------------------------------------------------
* ------------------------------------------------------------------------
* |     Smart-Shop开源商城系统/ Java商城-首选电商平台系统 请务必保留此注释头信息
* |     开源地址: https://gitee.com/ningbo-qishan/gruul-mall
* ------------------------------------------------------------------------
* ------------------------------------------------------------------------
* |     可正常分享和学习源码,未经授权 不可商用！
* |     商业版中台购买/开源版商业授权 联系技术客服
* |     官网:  https://www.73app.cn/
* ------------------------------------------------------------------------
* ------------------------------------------------------------------------
* |     Copyright (c) 2016-2999 宁波启山智软科技有限公司
* |     版权所有 ,侵权必究！
* ------------------------------------------------------------------------

*/
package com.medusa.gruul.finance.service.impl;

import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.medusa.gruul.common.core.exception.ServiceException;
import com.medusa.gruul.common.core.util.PageUtils;
import com.medusa.gruul.common.data.annotation.EscapeShop;
import com.medusa.gruul.common.data.annotation.EscapeTenant;
import com.medusa.gruul.finance.api.entity.FinanceAccount;
import com.medusa.gruul.finance.api.entity.FinanceBrokerageDetail;
import com.medusa.gruul.finance.api.entity.FinanceWithdrawalRecord;
import com.medusa.gruul.finance.api.enums.AccountTypeEnum;
import com.medusa.gruul.finance.api.enums.AuditStatusEnum;
import com.medusa.gruul.finance.api.enums.BrokerageTypeEnum;
import com.medusa.gruul.finance.api.enums.SettlementStatusEnum;
import com.medusa.gruul.finance.api.model.AddFinanceAccountDto;
import com.medusa.gruul.finance.mapper.FinanceAccountMapper;
import com.medusa.gruul.finance.mapper.FinanceWithdrawalRecordMapper;
import com.medusa.gruul.finance.model.ApiFinanceAccountVo;
import com.medusa.gruul.finance.service.IFinanceAccountService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.Arrays;
import java.util.List;

/**
 * <p>
 * 资金账户 服务实现类
 * </p>
 *
 * @author alan
 * @since 2020 -02-22
 */
@Slf4j
@Service
public class FinanceAccountServiceImpl extends ServiceImpl<FinanceAccountMapper, FinanceAccount> implements IFinanceAccountService {

    @Resource
    private FinanceWithdrawalRecordMapper financeWithdrawalRecordMapper;

    @Override
    public ApiFinanceAccountVo getFinanceAccountVo(AccountTypeEnum accountType, String userId) {
        FinanceAccount account = baseMapper.getByAccount(accountType, userId);
        if (ObjectUtil.isNull(account)) {
            throw new ServiceException(StrUtil.format("当前用户类型{}，用户ID{}无对应的账户", accountType.getDesc(), userId));
        }

        List<FinanceWithdrawalRecord> withdrawalRecordList =
                financeWithdrawalRecordMapper.selectList(new LambdaQueryWrapper<FinanceWithdrawalRecord>()
                        .eq(FinanceWithdrawalRecord::getAccountType, accountType)
                        .eq(FinanceWithdrawalRecord::getUserId, userId)
                        .in(FinanceWithdrawalRecord::getAuditStatus, Arrays.asList(0, 1))
                        .last("limit 1"));

        List<FinanceWithdrawalRecord> passRecordList =
                financeWithdrawalRecordMapper.selectList(new LambdaQueryWrapper<FinanceWithdrawalRecord>()
                        .eq(FinanceWithdrawalRecord::getAccountType, accountType)
                        .eq(FinanceWithdrawalRecord::getUserId, userId)
                        .eq(FinanceWithdrawalRecord::getAuditStatus, AuditStatusEnum.PASSED));

        ApiFinanceAccountVo vo = ApiFinanceAccountVo.toVo(account,
                passRecordList.stream().map(FinanceWithdrawalRecord::getAmount).reduce(BigDecimal.ZERO,
                        BigDecimal::add));
        if (withdrawalRecordList.isEmpty()) {
            vo.setWaitReviewedBrokerage(BigDecimal.ZERO);
        } else {
            vo.setWaitReviewedBrokerage(withdrawalRecordList.stream().map(FinanceWithdrawalRecord::getAmount).reduce(BigDecimal.ZERO,
                    BigDecimal::add));
        }
        return vo;
    }


    @Override
    public void addBrokerageFrozen(AccountTypeEnum accountType, Long userId, BigDecimal brokerage) {
        FinanceAccount account = baseMapper.getByAccount(accountType, userId.toString());
        if (ObjectUtil.isNotNull(account)) {
            account.setBrokerageFrozen(NumberUtil.add(account.getBrokerageFrozen(), brokerage));
            baseMapper.updateById(account);
        } else {
            log.error("当前用户类型{}，用户ID{}无对应的账户", accountType, userId.toString());
        }

    }

    @Override
    public void addBrokerage(AccountTypeEnum accountType, Long userId, BigDecimal brokerage) {
        FinanceAccount account = baseMapper.getByAccount(accountType, userId.toString());
        if (ObjectUtil.isNotNull(account)) {
            account.setBrokerageFrozen(NumberUtil.sub(account.getBrokerageFrozen(), brokerage));
            account.setBrokerage(NumberUtil.add(account.getBrokerage(), brokerage));
            account.setBrokerageTotal(NumberUtil.add(account.getBrokerageTotal(), brokerage));
            if (NumberUtil.isLess(account.getBrokerageFrozen(), BigDecimal.ZERO)) {
                throw new ServiceException("冻结佣金当前值为负数");
            }
            if (NumberUtil.isLess(account.getBrokerage(), BigDecimal.ZERO)) {
                throw new ServiceException("待提现佣金当前值为负数");
            }
            if (NumberUtil.isLess(account.getBrokerageTotal(), BigDecimal.ZERO)) {
                throw new ServiceException("总佣金当前值为负数");
            }
            baseMapper.updateById(account);
        } else {
            log.error("当前用户类型{}，用户ID{}无对应的账户", accountType, userId);
        }
    }


    @Override
    public void addAreaAssBrokerage(Long areaAssId, BigDecimal brokerage) {
        FinanceAccount account = baseMapper.getByAccount(AccountTypeEnum.AREA_ASS, areaAssId.toString());
        if (ObjectUtil.isNotNull(account)) {
            account.setBrokerage(NumberUtil.add(account.getBrokerage(), brokerage));
            account.setBrokerageTotal(NumberUtil.add(account.getBrokerageTotal(), brokerage));
            baseMapper.updateById(account);
        } else {
            log.error("当前用户类型{}，用户ID{}无对应的账户", AccountTypeEnum.AREA_ASS, areaAssId.toString());
        }
    }

    @Override
    public void subBrokerageFrozen(AccountTypeEnum accountType, Long userId, BigDecimal brokerage) {
        FinanceAccount account = baseMapper.getByAccount(accountType, userId.toString());
        if (ObjectUtil.isNotNull(account)) {
            account.setBrokerageFrozen(NumberUtil.sub(account.getBrokerageFrozen(), brokerage));
            baseMapper.updateById(account);
        }
    }


    @Override
    public FinanceAccount getByTypeAndId(AccountTypeEnum accountType, String userId) {
        return baseMapper.selectOne(new LambdaQueryWrapper<FinanceAccount>()
                .eq(FinanceAccount::getType, accountType)
                .in(FinanceAccount::getSourceId, userId)
        );
    }


    @Override
    public Boolean checkCost(AccountTypeEnum accountType, List<Long> ids) {
        List<FinanceAccount> accountList = baseMapper.selectList(new LambdaQueryWrapper<FinanceAccount>()
                .eq(FinanceAccount::getType, accountType)
                .in(FinanceAccount::getSourceId, ids)
        );
        for (FinanceAccount account : accountList) {
            if (NumberUtil.isGreater(account.getBrokerageFrozen(), BigDecimal.ZERO)) {
                log.error("当前用户类型{}，用户ID{}有未结算佣金{}", account.getType(), account.getId(), account.getBrokerageFrozen());
                return false;
            }
            if (NumberUtil.isGreater(account.getBrokerage(), BigDecimal.ZERO)) {
                log.error("当前用户类型{}，用户ID{}有未提现佣金{}", account.getType(), account.getId(), account.getBrokerage());
                return false;
            }
        }
        return true;
    }


    @Override
    public List<FinanceAccount> getByTypeAndIds(AccountTypeEnum accountType, List<Long> ids) {
        List<FinanceAccount> accountList = baseMapper.selectList(new LambdaQueryWrapper<FinanceAccount>()
                .eq(FinanceAccount::getType, accountType)
                .in(FinanceAccount::getSourceId, ids)
        );
        return accountList;
    }

    @Override
    @EscapeTenant
    @EscapeShop
    public FinanceAccount addAccount(AddFinanceAccountDto dto) {
        FinanceAccount account = baseMapper.getByAccount(dto.getType(), dto.getId());
        if (ObjectUtil.isNull(account)) {
            account = new FinanceAccount();
            account.setShopId(dto.getShopId());
            account.setUserId(dto.getUserId());
            account.setBrokerageTotal(BigDecimal.ZERO);
            account.setBrokerage(BigDecimal.ZERO);
            account.setBrokerageFrozen(BigDecimal.ZERO);
            account.setType(dto.getType());
            account.setSourceId(dto.getId());
            account.setTenantId(dto.getTenantId());
            baseMapper.insert(account);
        }
        return account;
    }


}


